/*
  The <pmode.h> header file defines some functions used by the kernel to handle Protected Mode instructions at IOPL 0
*/

#ifndef _PMODE_H
#define _PMODE_H

/* from lib files */
#include <types.h>

/* from kernel files */
#include <hardware.h>


/* Access byte flags */
/* bit 7 */
#define ACS_PRESENT      0x80            /* present segment */
/* bits 6,5 */
#define ACS_DPL0         0x00             /* descriptor privilege level 0 */
#define ACS_DPL1         0x20             /* descriptor privilege level 1 */
#define ACS_DPL2         0x40             /* descriptor privilege level 2 */
#define ACS_DPL3         0x60             /* descriptor privilege level 3 */
/* bit 4 */
#define ACS_SYSTEM       0x00             /* system segment */
#define ACS_NOT_SYSTEM   0x10             /* non-system segment (code,data,stack) */
/* bit 3 */
#define ACS_EXEC         0x08             /* executable segment */
/* data: bit 2 */
#define ACS_EXPAND_UP    0x00             /* data segment expands upwards (offset<=limit) */
#define ACS_EXPAND_DOWN  0x04             /* data segment expands downwards (offset>limit) */
/* code: bit 2 */
#define ACS_CONFORMING   0x04             /* code segment is conforming (exec if cpl>=dpl) */
/* data: bit 1 */
#define ACS_WRITE        0x02             /* writable data segment */
/* code: bit 1 */
#define ACS_READ         0x02             /* readable code segment */
/* bit 0 */
#define ACS_ACCESSED     0x01             /* segment is accessed */

/* Gran byte flags */
/* bit 7 */
#define GRAN_BYTE        0x00             /* segment is Byte granular */ 
#define GRAN_PAGE        0x80             /* segment is Page granular */ 
/*bit 6 */
#define GRAN_BIT16       0x00             /* default operand sizes are 16 bit */ 
#define GRAN_BIT32       0x40             /* default operand sizes are 32 bit */ 


/* Ready made descriptors */
#define GDT_TYPE_DATA    (ACS_PRESENT | ACS_NOT_SYSTEM | ACS_EXPAND_UP | ACS_WRITE)
#define GDT_TYPE_CODE    (ACS_PRESENT | ACS_NOT_SYSTEM | ACS_EXEC | ACS_READ)
#define GDT_TYPE_TSS     (ACS_PRESENT | ACS_SYSTEM | ACS_EXEC | ACS_ACCESSED)

#define IDT_TYPE_TRAP    (ACS_PRESENT | ACS_DPL3 | ACS_SYSTEM | ACS_EXEC | ACS_CONFORMING | ACS_READ | ACS_ACCESSED)
#define IDT_TYPE_INTR    (ACS_PRESENT | ACS_DPL3 | ACS_SYSTEM | ACS_EXEC | ACS_CONFORMING | ACS_READ)
#define IDT_TYPE_TGATE   (ACS_PRESENT | ACS_SYSTEM | ACS_CONFORMING | ACS_ACCESSED)


/* GDT and IDT related values */

#define DESC_SIZE       8                 /* size of a generic descriptor */
#define IDT_ENTRIES    64      /* 200 */
#define GDT_ENTRIES     6


/*
#define IDT_BASE        0
#define IDT_LIMIT       DESC_SIZE*IDT_ENTRIES-1
#define GDT_BASE        IDT_BASE+IDT_LIMIT+1
#define GDT_LIMIT       DESC_SIZE*GDT_ENTRIES-1
*/

#define GDT_DESC_NULL       0x0000
#define GDT_DESC_CODE       0x0008
#define GDT_DESC_DATA       0x0010
#define GDT_DESC_UCODE      0x0018
#define GDT_DESC_UDATA      0x0020
#define GDT_DESC_TSS        0x0028

//#define GDT_DESC_INIT       0x0018
//#define GDT_DESC_TASKA      0x0020
//#define GDT_DESC_TASKB      0x0028


/* GDTR and IDTR Registers definitions */

/* align structures to one Byte boundary */

//#pragma pack(push,1)
#pragma pack(1)

/* GDTR register definition */
typedef struct {
  word_t limit;
  dword_t base;
} GDTR_T;

/* IDTR register definition */
typedef struct {
  word_t limit;
  dword_t base;
} IDTR_T;


/* Descriptor definitions */

/* Global desciptor definition (code, data, tss) */
typedef struct {
  word_t limit_0_15,
         base_0_15;
  byte_t base_16_23,
         access,
         gran,
         base_24_31;
} GDT_Entry_T;

/* Interrupt desciptor definition */
typedef struct {
  word_t offset_0_15,
         selector;
  byte_t not_used,
         access;
  word_t offset_16_31;
} IDT_Entry_T;


/* Task Gate desciptor definition */
typedef struct {
  word_t not_used_0,
         selector;
  byte_t not_used_1,
         access;
  word_t not_used_2;
} TGATE_Entry_T;


/* Task State Segment (TSS) definition */
typedef struct {        /* TSS for 386+ */
  dword_t backlink,
        esp0,
        ss0,
        esp1,
        ss1,
        esp2,
        ss2,
        cr3,
        eip,
        eflags,
        eax,
        ecx,
        edx,
        ebx,
        esp,
        ebp,
        esi,
        edi,
        es,
        cs,
        ss,
        ds,
        fs,
        gs,
        ldtr;
  word_t  trace,
        iomap_base;
} TSS_T;

/* align structures to default boundary */

//#pragma pack(pop)
#pragma pack(4)


extern void setup_IDT_Entry(IDT_Entry_T *entry, byte_t type, word_t selector, dword_t isr);
extern void setup_GDT_Entry(GDT_Entry_T *entry, byte_t gran, byte_t access, dword_t base, word_t limit);

extern void place_IDT_Entry(int num,IDT_Entry_T *desc);
extern void place_GDT_Entry(int num,GDT_Entry_T *desc);

extern void prepare_IDT(void);
extern void prepare_GDT(void);
extern void prepare_TSS(void);

extern void enable_interrupts(void);
extern void disable_interrupts(void);

#endif /* _PMODE_H */

